import { _decorator, Component, EventTouch, Material, Node, Sprite, UIOpacity, UITransform, v3, Vec2, Vec3 } from 'cc';
import { AudioManager } from '../AudioManager';
import { Url } from '../Url';
import { BlockControllerPure } from './Block/BlockControllerPure';
import { BlockConfig, BlocksAll, BlockState, ReConfig, Region } from './Block/BlockData';
import GlobalData from './GlobalData';
import { GridBlockMgrPure } from './GridBlockMgrPure';
import { GuidePure } from './GuidePure';
import { MainGameLogicPure } from './MainGameLogicPure';
const { ccclass, property } = _decorator;


@ccclass('TouchMgrPure')
export class TouchMgrPure extends Component {

    /** 单例模式 */
    private static _ins: TouchMgrPure;
    constructor() {
        super();
        TouchMgrPure._ins = this;
    }
    public static get ins(): TouchMgrPure {
        if (!TouchMgrPure._ins) {
            TouchMgrPure._ins = new TouchMgrPure();
        }
        return TouchMgrPure._ins;
    }



    @property(Node)
    selection_container: Node = null;

    @property(Node)
    select1: Node = null;
    @property(Node)
    select2: Node = null;
    @property(Node)
    select3: Node = null;

    selectCanTouch: boolean[] = [false, false, false]

    @property(Node)
    tempBlock: Node = null;

    @property(Material)
    material: Material = null;

    @property(Material)
    defaultmaterial: Material = null;

    posOffset: Vec3 = new Vec3(0, 0, 0);
    offsetVector: Vec3 = new Vec3(0, 200, 0);

    isCanPlaced: boolean = false;
    placedIndexArr: number[] = [];

    private longPressThreshold: number = 80; // 长按阈值，单位毫秒
    private longPressTimer: any = null;
    private isLongPress: boolean = false;

    vec3Reusable: Vec3 = new Vec3();

    private enlargedBlocks: Node[] = []; // 记录上一次放大的块

    onLoad() {
        this.select1.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
        this.select1.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
        this.select1.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
        this.select1.on(Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);

        this.select2.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
        this.select2.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
        this.select2.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
        this.select2.on(Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);

        this.select3.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
        this.select3.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
        this.select3.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
        this.select3.on(Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
    }

    start() {
        // log(this.selectCanTouch)
        // const p = this.getRegion(new Vec3(0, 300, 0));
        // console.log(GridBlockMgrPure.ins.block_ba_data[p.i][p.j].block_ba_node.position);
        // console.log(GridBlockMgrPure.ins.block_ba_data[p.i][p.j].index_i, GridBlockMgrPure.ins.block_ba_data[p.i][p.j].index_j);

    }

    update(deltaTime: number) {

    }

    onTouchStart(event: EventTouch) {
        
        this.resumePromptBlock();
        let touch_node = event.getCurrentTarget() as Node;
        let touchSelectIndex = touch_node.getSiblingIndex();
        if (!this.selectCanTouch[touchSelectIndex]) {
            return;
        }
        AudioManager.ins.playOneShot(Url.AUDIO.SFX2, 1);
        this.isLongPress = false;

        this.longPressTimer = setTimeout(() => {
            this.isLongPress = true;
            touch_node.children[1].active = false;

            // 获取点击的目标block
            let target_block = touch_node.children[0];

            // 获取block的BlockController组件中的BlockConfig数据
            let target_block_config: BlockConfig = target_block.getComponent(BlockControllerPure).curBlockConfig;

            // 点击之后下方展示block隐藏
            target_block.active = false;

            // 生成一个要跟随鼠标移动的临时block，并将位置放在鼠标点击位置
            this.tempBlock.active = true;
            this.tempBlock.getComponent(BlockControllerPure).updateBlockSet(false, target_block_config);
            const touch_pos = event.getUILocation();
            const temp_touch_pos = this.getRelativePosition(this.selection_container, this.vec2ToVec3(touch_pos));

            // 设置临时block的位置到点击位置
            this.tempBlock.setPosition(temp_touch_pos.add(new Vec3(0, 250, 0))); // 将tempBlock位置放在点击位置的上方200处

            this.tempBlock.getComponent(BlockControllerPure).addBlockOffset(2);

            // 获取临时tempBlock和鼠标之间的向量差
            // this.posOffset = this.vectorDifference(temp_touch_pos, this.tempBlock.position);
        }, this.longPressThreshold);
    }

    onTouchMove(event: EventTouch) {
        this.resumePromptBlock();
        let touch_node = event.getCurrentTarget() as Node;
        let touchSelectIndex = touch_node.getSiblingIndex();
        if (!this.selectCanTouch[touchSelectIndex]) {
            return;
        }
        touch_node.children[1].active = false;

        // 获取鼠标当前位置并转换
        let touch_pos = event.getUILocation();
        // let temp_touch_pos = this.getRelativePosition(this.selection_container, this.vec2ToVec3(touch_pos));
        const temp_touch_pos = this.getRelativePosition(this.selection_container, this.vec2ToVec3(touch_pos));

        // 设置临时block的位置到点击位置
        this.tempBlock.setPosition(temp_touch_pos.add(new Vec3(0, 250, 0))); // 将tempBlock位置放在点击位置的上方200处

        this.tempBlock.getComponent(BlockControllerPure).addBlockOffset(2);

        let pos_to_grid = this.getNodeAToNodeBPoint(GridBlockMgrPure.ins.gridcontainer.parent, this.tempBlock);
        let indexi_j = this.getRegion(new Vec3(pos_to_grid.x, pos_to_grid.y, 0));

        GridBlockMgrPure.ins.updateBoard();

        if (indexi_j) {
            let date = GridBlockMgrPure.ins.block_ba_data[indexi_j.i][indexi_j.j];
            let tempBlockData = this.tempBlock.getComponent(BlockControllerPure).curBlockConfig;
            if (!tempBlockData) {
                return;
            }
            let config = this.getCenteredBlocks(date.index_i, date.index_j, tempBlockData.block_arr, this.tempBlock);
            // console.log(config);

            this.isCanPlaced = config.iscanplaced;
            this.placedIndexArr = config.indexarr;
        } else {
            this.isCanPlaced = false;
        }
    }

    onTouchEnd(event: EventTouch) {
        this.resumePromptBlock();
        let touch_node = event.getCurrentTarget() as Node;
        let touchSelectIndex = touch_node.getSiblingIndex();
        if (!this.selectCanTouch[touchSelectIndex]) {
            return;
        }

        if (this.longPressTimer) {
            clearTimeout(this.longPressTimer);
            this.longPressTimer = null;
        }

        if (this.isLongPress) {
            touch_node.children[1].active = false;

            GridBlockMgrPure.ins.updateBoard();

            if (this.isCanPlaced) {
                AudioManager.ins.playOneShot(Url.AUDIO.SFX3, 1);
                this.tempBlock.active = false;
                for (let i = 0; i < this.placedIndexArr.length; i++) {
                    let boardindex_i = this.placedIndexArr[i][0];
                    let boardindex_j = this.placedIndexArr[i][1];
                    GridBlockMgrPure.ins.block_ba_data[boardindex_i][boardindex_j].block_state = BlockState.SHOW;
                    GridBlockMgrPure.ins.block_ba_data[boardindex_i][boardindex_j].block_ba_node.getComponent(UIOpacity).opacity = 255;
                }
                this.selectCanTouch[touch_node.getSiblingIndex()] = false;

                let is_empty = this.selectionConEmpty();
                if (is_empty && GlobalData.guideRecord > 3) {
                    GridBlockMgrPure.ins.generateSpecificSelectionBlock(false);
                }
                let effectpos = GridBlockMgrPure.ins.checkAndUpdateBlocks();
                MainGameLogicPure.ins.shwoGetCashEffect(effectpos);

            } else {
                let targetBlock = touch_node.children[0];
                targetBlock.active = true;
                this.tempBlock.active = false;
            }

            this.isCanPlaced = false;

            if (!GlobalData.isCommer) {
                let isOver = GridBlockMgrPure.ins.detectGameOver();
                // console.log(isOver);

                if (isOver) {
                    for (let i = 0; i < GridBlockMgrPure.ins.selects.length; i++) {
                        GridBlockMgrPure.ins.selects[i].getComponent(BlockControllerPure).checkGray();
                        // GridBlockMgrPure.ins.selects[i].parent.getChildByName('frash').active = false;
                    }
                    MainGameLogicPure.ins.gameOver();
                }

            }

        } else {
            if (GlobalData.isCommer) {
                return
            }
            let target_block_config = touch_node.children[0].getComponent(BlockControllerPure).curBlockConfig;
            if (target_block_config.block_type != 0 && target_block_config.block_type != 4 && target_block_config.block_type != 5) {
                touch_node.children[1].active = true;
            }

            let new_target_block_arr = this.rotateMatrix(target_block_config.block_arr);
            const matchingBlockConfig = this.findMatchingBlockConfig(new_target_block_arr);
            touch_node.children[0].getComponent(BlockControllerPure).updateBlockSet(true, matchingBlockConfig);
            touch_node.children[0].setPosition(Vec3.ZERO);
            touch_node.children[0].getComponent(BlockControllerPure).addBlockOffset(4);
            if (!GlobalData.isCommer) {
                let isOver = GridBlockMgrPure.ins.detectGameOver();
                console.log(isOver);

                if (isOver) {
                    for (let i = 0; i < GridBlockMgrPure.ins.selects.length; i++) {
                        GridBlockMgrPure.ins.selects[i].getComponent(BlockControllerPure).checkGray();
                        // GridBlockMgrPure.ins.selects[i].parent.getChildByName('frash').active = false;
                    }
                    MainGameLogicPure.ins.gameOver();
                }

            }
        }
    }

    //  判断数组一致性
    arraysEqual(arr1: number[][], arr2: number[][]): boolean {
        if (arr1.length !== arr2.length) return false;
        for (let i = 0; i < arr1.length; i++) {
            if (arr1[i].length !== arr2[i].length) return false;
            for (let j = 0; j < arr1[i].length; j++) {
                if (arr1[i][j] !== arr2[i][j]) return false;
            }
        }
        return true;
    }

    //  根据旋转后的二维数组，找到匹配的数据
    findMatchingBlockConfig(arr: number[][]): BlockConfig | null {

        for (const block of BlocksAll) {
            if (this.arraysEqual(block.block_arr, arr)) {
                return block;
            }
        }
        return null;
    }

    getRegion(pos: Vec3): Region | null {
        const nodeSize = 980; // 节点的大小
        const gridSize = 8; // 区域的数量
        const cellSize = 122.5; // 每个区域块的大小

        // 中心点的偏移量
        const halfNodeSize = nodeSize / 2;

        // 转换坐标到以中心点为原点的坐标系
        const localX = pos.x + halfNodeSize;
        const localY = pos.y + halfNodeSize;

        // 计算坐标所在的区域块索引
        const i = Math.floor((localY) / cellSize);
        const j = gridSize - 1 - Math.floor(localX / cellSize);

        // 检查索引是否在有效范围内
        if (i >= 0 && i < gridSize && j >= 0 && j < gridSize) {
            return { i, j };
        } else {
            return null;
        }
    }

    getCenteredBlocks(index_i: number, index_j: number, curBlockArr: number[][], tempBlock: Node): ReConfig {
        if (!curBlockArr) {
            this.resumePromptBlock();
            return { iscanplaced: false, indexarr: null };
        }

        // 检查是否处于引导状态，并验证当前位置是否符合引导位置
        if (GlobalData.isCommer) {
            this.resumePromptBlock();
            if ((GlobalData.guideRecord == 1 && (index_i != GuidePure.ins.guideindex1[0] || index_j != GuidePure.ins.guideindex1[1])) ||
                (GlobalData.guideRecord == 2 && (index_i != GuidePure.ins.guideindex2[0] || index_j != GuidePure.ins.guideindex2[1])) ||
                (GlobalData.guideRecord == 3 && (index_i != GuidePure.ins.guideindex3[0] || index_j != GuidePure.ins.guideindex3[1]))) {

                return { iscanplaced: false, indexarr: null };
            }
        }

        const blocks: (number | null)[][] = Array(5).fill(null).map(() => Array(5).fill(null));
        const blocks_ba_node: (Node | null)[][] = Array(5).fill(null).map(() => Array(5).fill(null));
        const blocks_index: (number[] | null)[][] = Array(5).fill(null).map(() => Array(5).fill(null));

        const startI = Math.max(index_i - 2, 0);
        const endI = Math.min(index_i + 2, GridBlockMgrPure.ins.block_ba_data.length - 1);
        const startJ = Math.max(index_j - 2, 0);
        const endJ = Math.min(index_j + 2, GridBlockMgrPure.ins.block_ba_data[0].length - 1);

        for (let i = startI; i <= endI; i++) {
            for (let j = startJ; j <= endJ; j++) {
                const block = GridBlockMgrPure.ins.block_ba_data[i][j].block_state;
                const block_ba_node = GridBlockMgrPure.ins.block_ba_data[i][j].block_ba_node;
                const block_index = [GridBlockMgrPure.ins.block_ba_data[i][j].index_i, GridBlockMgrPure.ins.block_ba_data[i][j].index_j];
                blocks[i - (index_i - 2)][j - (index_j - 2)] = block;
                blocks_ba_node[i - (index_i - 2)][j - (index_j - 2)] = block_ba_node;
                blocks_index[i - (index_i - 2)][j - (index_j - 2)] = block_index;
            }
        }

        // 检查当前位置是否可以放置块
        for (let i = 0; i < 5; i++) {
            for (let j = 0; j < 5; j++) {
                const block = blocks[i][j];
                const curBlock = curBlockArr[i][j];
                if ((block === 1 && curBlock === 1) || (block === null && curBlock === 1)) {
                    this.resumePromptBlock();
                    return { iscanplaced: false, indexarr: null };
                }
            }
        }

        let returnIndexArr = [];
        // 显示提示位置
        for (let i = 0; i < 5; i++) {
            for (let j = 0; j < 5; j++) {
                const block = blocks[i][j];
                const curBlock = curBlockArr[i][j];
                if (block === 0 && curBlock === 1) {
                    blocks_ba_node[i][j].getComponent(UIOpacity).opacity = 150;
                    returnIndexArr.push(blocks_index[i][j]);
                }
            }
        }

        // 处理 tempBlock 的 25 个子节点并建立映射关系
        const tempBlockChildren = tempBlock.children;
        const tempBlockArr: (Node | null)[][] = Array(5).fill(null).map(() => Array(5).fill(null));
        for (let i = 0; i < 5; i++) {
            for (let j = 0; j < 5; j++) {
                tempBlockArr[i][j] = tempBlockChildren[i * 5 + j];
            }
        }

        // 创建临时棋盘数据对象，并模拟 tempBlock 已经放置
        const tempGrid = Array(8).fill(null).map(() => Array(8).fill(0));
        for (let i = 0; i < 8; i++) {
            for (let j = 0; j < 8; j++) {
                tempGrid[i][j] = GridBlockMgrPure.ins.block_ba_data[i][j].block_state;
            }
        }

        // 模拟放置 curBlockArr 到临时棋盘上
        for (let i = 0; i < 5; i++) {
            for (let j = 0; j < 5; j++) {
                if (curBlockArr[i][j] === 1) {
                    const gridI = index_i - 2 + i;
                    const gridJ = index_j - 2 + j;
                    if (gridI >= 0 && gridI < 8 && gridJ >= 0 && gridJ < 8) {
                        tempGrid[gridI][gridJ] = 1;
                    }
                }
            }
        }

        // 检查临时棋盘是否有可消除的行或列
        let canEliminate = false;
        const rowsToCheck = [];
        const colsToCheck = [];

        for (let i = 0; i < 8; i++) {
            if (tempGrid[i].every(value => value === 1)) {
                canEliminate = true;
                rowsToCheck.push(i);
            }
            if (tempGrid.every(row => row[i] === 1)) {
                canEliminate = true;
                colsToCheck.push(i);
            }
        }

        if (canEliminate) {
            // 放大真实棋盘上可消除的块
            rowsToCheck.forEach(row => {
                for (let j = 0; j < 8; j++) {
                    const blockNode = GridBlockMgrPure.ins.block_ba_data[row][j].block_ba_node;
                    if (blockNode && GridBlockMgrPure.ins.block_ba_data[row][j].block_state === BlockState.SHOW) {
                        blockNode.getComponent(Sprite).material = this.material;
                        this.enlargedBlocks.push(blockNode); // 记录放大的块
                    }
                }
            });
            5
            colsToCheck.forEach(col => {
                for (let i = 0; i < 8; i++) {
                    const blockNode = GridBlockMgrPure.ins.block_ba_data[i][col].block_ba_node;
                    if (blockNode && GridBlockMgrPure.ins.block_ba_data[i][col].block_state === BlockState.SHOW) {
                        blockNode.getComponent(Sprite).material = this.material;
                        this.enlargedBlocks.push(blockNode); // 记录放大的块
                    }
                }
            });

            // 放大 tempBlock 中会产生消除的块
            for (let i = 0; i < 5; i++) {
                for (let j = 0; j < 5; j++) {
                    if (curBlockArr[i][j] === 1) {
                        const gridI = index_i - 2 + i;
                        const gridJ = index_j - 2 + j;
                        if (rowsToCheck.includes(gridI) || colsToCheck.includes(gridJ)) {
                            tempBlockArr[i][j].getComponent(Sprite).material = this.material;
                            this.enlargedBlocks.push(tempBlockArr[i][j]); // 记录放大的块
                        }
                    }
                }
            }
        } else {
            this.resumePromptBlock();
        }

        return { iscanplaced: true, indexarr: returnIndexArr };
    }

    resumePromptBlock() {
        // 恢复上一次放大的块大小
        this.enlargedBlocks.forEach(node => {
            node.getComponent(Sprite).material = this.defaultmaterial;
        });
        this.enlargedBlocks = []; // 清空放大块的记录
    }



    /**
     * 获取坐标在目标节点（容器）下的相对位置
     * @param container 目标节点（容器）
     * @param nodepos 已有node节点坐标可传
     */
    public getRelativePosition(container: Node, nodepos?: Vec3,): Vec3 {
        //const worldPos = (node.getParent() || node).getComponent(UITransform).convertToWorldSpaceAR(nodepos ? nodepos : node.getPosition());
        return container.getComponent(UITransform).convertToNodeSpaceAR(nodepos);
    }

    /**
    * 获取A相对B的局部坐标
    * @param {*} nodeA 
    * @param {*} nodeB 
    */
    public getNodeAToNodeBPoint(nodeA: Node, nodeB: Node) {
        var nodeAWorldPoint = nodeA.getComponent(UITransform).convertToWorldSpaceAR(Vec3.ZERO);
        //console.log("nodeAWorldPoint",nodeAWorldPoint);
        var AToBPos = nodeB.getComponent(UITransform).convertToNodeSpaceAR(nodeAWorldPoint);

        return v3(AToBPos.x, AToBPos.y, 1) //{ x: AToBPos.x, y: AToBPos.y };
    }
    /**
     * 计算两个向量的差
     * @param vec1 向量1
     * @param vec2 向量2
     * @returns 
     */
    vectorDifference(vec1: Vec3, vec2: Vec3): Vec3 {
        // 使用 cc.Vec3 的 subtract 方法计算向量差
        const result = new Vec3();
        Vec3.subtract(result, vec1, vec2);
        return result;
    }
    /**
     * 
     * @param arr 判断选择区是否已经清空
     * @returns 
     */
    selectionConEmpty(): boolean {
        for (let i = 0; i < this.selectCanTouch.length; i++) {
            if (this.selectCanTouch[i] !== false) {
                return false;
            }
        }
        return true;
    }
    /**
     * 二维数组旋转
     * @param matrix 二维矩阵
     * @param clockwise 是否顺时针
     * @returns 
     */
    rotateMatrix(matrix: any[][], clockwise: boolean = true): any[][] {
        const N = matrix.length;
        const rotatedMatrix: any[][] = [];

        for (let i = 0; i < N; i++) {
            rotatedMatrix.push([]);
        }

        for (let i = 0; i < N; i++) {
            for (let j = 0; j < N; j++) {
                if (clockwise) {
                    rotatedMatrix[j][N - 1 - i] = matrix[i][j];
                } else {
                    rotatedMatrix[N - 1 - j][i] = matrix[i][j];
                }
            }
        }

        return rotatedMatrix;
    }


    /**
     * Vec2转Vec3
     * @param vec2 一个Vec2
     * @returns 一个Vec3
     */
    vec2ToVec3(vec2: Vec2): Vec3 {
        this.vec3Reusable.set(vec2.x, vec2.y, 0);
        return this.vec3Reusable;
    }


}

